/**
 * Title: PermitCoreServiceImpl.java
 * Description: Copyright: Copyright (c) 2019 Company: BHFAE
 *
 * @author Sharp
 * @date 2019-7-31 16:04
 * @description Project Name: Grote
 * @Package: com.srct.service.account.service.impl
 */
package com.sharp.authorization.service.permit.impl;

import com.sharp.authorization.bo.permit.PermitInfo;
import com.sharp.authorization.constants.common.ClientTypeConst;
import com.sharp.authorization.constants.token.TokenItemConst;
import com.sharp.authorization.dao.common.entity.AcPermit;
import com.sharp.authorization.dao.common.entity.AcRolePermit;
import com.sharp.authorization.dao.common.repository.AcPermitService;
import com.sharp.authorization.dao.common.repository.AcRolePermitService;
import com.sharp.authorization.dao.common.repository.AcUserRoleService;
import com.sharp.authorization.dao.common.repository.UserPermitService;
import com.sharp.authorization.service.permit.PermitCoreService;
import com.sharp.authorization.service.token.TokenService;
import com.sharp.authorization.vo.permit.*;
import com.sharp.kernel.constant.CommonConst;
import com.sharp.kernel.constant.db.SqlConstant;
import com.sharp.kernel.constant.err.ErrCodeSys;
import com.sharp.kernel.utils.ReflectionUtil;
import com.sharp.kernel.validate.Validator;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

@Service
public class PermitCoreServiceImpl implements PermitCoreService {

    @Resource
    private UserPermitService userPermitService;
    @Resource
    private AcPermitService acPermitService;
    @Resource
    private TokenService tokenService;
    @Resource
    private AcRolePermitService acRolePermitService;
    @Resource
    private AcUserRoleService acUserRoleService;

    @Override
    public List<PermitRes> getAllPermit() {
        List<AcPermit> permitList = acPermitService.select();
        return ReflectionUtil.copyList(permitList, PermitRes.class);
    }

    @Override
    public List<PermitRes> getAllPermitByClientType(String clientType) {
        List<AcPermit> permitList = acPermitService.getAllPermitByClientType(clientType);
        return ReflectionUtil.copyList(permitList, PermitRes.class);
    }

    @Override
    public List<AllPermitTreeRes> getAllPermitTree(String clientType) {
        List<AllPermitTreeRes> res = new ArrayList<>();
        if (StringUtils.isNotBlank(clientType)) {
            List<PermitTreeRes> menuList = getPermitTreeRes(clientType);
            if (CollectionUtils.isNotEmpty(menuList)) {
                res.add(buildAllPermitTreeRes(clientType, menuList));
            }
        } else {
            for (ClientTypeConst clientTypeEnum : ClientTypeConst.values()) {
                List<PermitTreeRes> menuList = getPermitTreeRes(clientTypeEnum.name());
                if (CollectionUtils.isNotEmpty(menuList)) {
                    res.add(buildAllPermitTreeRes(clientTypeEnum.name(), menuList));
                }
            }
        }
        return res;
    }

    @Override
    public List<PermitRes> getPermitListByCustomerNumber(String customerNumber, String clientType) {
        List<AcPermit> permitList = userPermitService.getPermitListByCustomerNumber(customerNumber, clientType);
        return ReflectionUtil.copyList(permitList, PermitRes.class);
    }

    @Override
    public List<PermitRes> getPermitListByUserId(String userId, String clientType) {
        List<AcPermit> permitList = userPermitService.getPermitListByUserId(userId, clientType);
        return ReflectionUtil.copyList(permitList, PermitRes.class);
    }

    @Override
    public List<PermitTreeRes> getPermitTree() {
        List<PermitRes> permitList = tokenService.getItem(TokenItemConst.PERMIT_TREE.name(), List.class, PermitRes.class);
        return buildPermitTree(permitList);
    }

    @Override
    public List<PermitRes> getRolePermitList(List<String> roleIdList) {
        List<AcRolePermit> acRolePermitList = acRolePermitService.select("roleId", roleIdList);
        List<String> permitIdList = ReflectionUtil.getFieldList(acRolePermitList, "permitId", String.class);
        List<AcPermit> permitList = acPermitService.select("id", permitIdList);
        return ReflectionUtil.copyList(permitList, PermitRes.class);
    }

    @Override
    public List<PermitRes> getRolePermitList(List<String> roleIdList, String clientType) {
        List<AcRolePermit> acRolePermitList = acRolePermitService.select("roleId", roleIdList);
        List<String> permitIdList = ReflectionUtil.getFieldList(acRolePermitList, "permitId", String.class);
        List<AcPermit> permitList = acPermitService.getPermitByIdListAndClientType(permitIdList, clientType);
        return ReflectionUtil.copyList(permitList, PermitRes.class);
    }

    @Override
    public List<PermitTreeRes> getUserPermitTree(String userId, String clientType) {
        List<PermitRes> boList = getPermitListByUserId(userId, clientType);
        return buildPermitTree(boList);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void bindUserRole(BindUserRoleReq req) {
        acUserRoleService.deleteByUserId(req.getUserId());
        acUserRoleService.bind(req.getUserId(), req.getRoleIdList());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void bindRolePermit(BindRolePermitReq req) {
        acRolePermitService.deleteByRoleId(req.getRoleId());
        acRolePermitService.bind(req.getRoleId(), req.getPermitList());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void addPermit(AddPermitReq req) {
        AcPermit permit = ReflectionUtil.copy(req, AcPermit.class);
        permit.setStatus(CommonConst.YES);
        permit.setValid(SqlConstant.VALID);
        acPermitService.insertSelective(permit);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updatePermit(UpdatePermitReq req) {
        AcPermit permit = ReflectionUtil.copy(req, AcPermit.class);
        permit.setValid(SqlConstant.VALID);
        acPermitService.updateByPrimaryKeySelective(permit);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deletePermit(DeletePermitReq req) {
        int count = acRolePermitService.countByPermitId(req.getId());
        Validator.assertTrue(count == 0, ErrCodeSys.SYS_ERR_MSG, "该菜单隶属于" + count + "个角色, 不可删除");
        List<AcPermit> permitList = acPermitService.getPermitListByParentId(req.getId());
        Validator.assertTrue(CollectionUtils.isEmpty(permitList), ErrCodeSys.SYS_ERR_MSG, "有子菜单,不可删除");
        AcPermit permit = ReflectionUtil.copy(req, AcPermit.class);
        acRolePermitService.deleteByRoleId(permit.getId());
        acPermitService.deleteByPrimaryKey(permit);
    }

    private List<PermitTreeRes> getPermitTreeRes(String clientType) {
        List<PermitRes> permitResList = getAllPermitByClientType(clientType);
        return buildPermitTree(permitResList);
    }

    private AllPermitTreeRes buildAllPermitTreeRes(String clientType, List<PermitTreeRes> menuList) {
        AllPermitTreeRes res = new AllPermitTreeRes();
        res.setClientType(clientType);
        res.setSubMenu(menuList);
        return res;
    }

    private List<PermitTreeRes> buildPermitTree(List<PermitRes> permitList) {
        List<PermitTreeRes> res = new ArrayList<>();
        List<PermitInfo> parentMenuList =
                permitList.stream().filter(permit -> permit.getParentPermitId() == null).collect(Collectors.toList());
        parentMenuList.forEach(parentMenu -> res.add(buildPermitTree(parentMenu, permitList, 0)));
        return res;
    }

    private PermitTreeRes buildPermitTree(PermitInfo parentMenu, List<PermitRes> permitList, int level) {
        PermitTreeRes menu = ReflectionUtil.copy(parentMenu, PermitTreeRes.class);
        menu.setLevel(level);
        List<PermitInfo> menuList =
                permitList.stream().filter(permit -> parentMenu.getId().equals(permit.getParentPermitId()))
                        .collect(Collectors.toList());
        for (PermitInfo subMenu : menuList) {
            menu.getSubMenu().add(buildPermitTree(subMenu, permitList, level + 1));
        }
        return menu;
    }
}
